package GenericBox2;

import junit.framework.TestCase;


public class Test_Box extends TestCase {
  
  public void test_OldBox() {
    OldBox box = new OldBox(42);
    
    // Show that what you put in is what you get out.
    assertEquals("Box(42).getData()", 42, box.getData());
    
    // The following line should not compile -- "incompatible type" error.
    //intBox = new Box<String>("Hello");
    
    // The following line gives a "cannot find symbol" error when 
    // compiled because the constructor call doesn't match its defined signature.
    //intBox = new Box<Integer>("Hello");
    
    // Verify the type of the returned object.
    assertEquals("OldBox.getData()type", "class java.lang.Integer", box.getData().getClass().toString());
    
    // no problem with assigning to the same type
    int x = (Integer) box.getData();
    
    // compiler allows an illegal assignment to a different type
    try {
      String s = (String) box.getData();
      fail("Should not allow casting of an Integer to a String");
    }
    catch(ClassCastException e) {
      // This is the proper exception here.
    }
    catch(Exception e) {
      fail("Wrong exception: "+ e);
    }
    
    box = new OldBox("Howdy");
    
    // Show that what you put in is what you get out.
    assertEquals("Box(Howdy).getData()", "Howdy", box.getData());
    // Verify the type of the returned object.
    assertEquals("OldBox.getData()type", "class java.lang.String", box.getData().getClass().toString());
    
  }
  
  public void test_Box() {
    Box<Integer> intBox = new Box<Integer>(42);
    
    // Show that what you put in is what you get out.
    assertEquals("Box(42).getData()", "42", intBox.getData());
    
    // The following line should not compile -- "incompatible type" error.
    //intBox = new Box<String>("Hello");
    
    // The following line gives a "cannot find symbol" error when 
    // compiled because the constructor call doesn't match its defined signature.
    //intBox = new Box<Integer>("Hello");
    
    // This assignment is no problem because the types are the same.  
    // Note that no cast is needed because Boc<Integer>.getData() is 
    // already defined as returning an Integer.
    int x = intBox.getData();
    
    // The compiler will not allow the assignment because the types are incompatible
    // with or without the cast.
    //  String s = (String) intBox.getData();
    
    
    // Verify the type of the returned object.
    assertEquals("Box<Integer>.getData()type", "class java.lang.Integer", intBox.getData().getClass().toString());
    
    Box<String> strBox = new Box<String>("Howdy");
    
    // Show that what you put in is what you get out.
    assertEquals("Box(Howdy).getData()", "Howdy", strBox.getData());
    // Verify the type of the returned object.
    assertEquals("Box<String>.getData()type", "class java.lang.String", strBox.getData().getClass().toString());
    
    // Evidence of type erasure by the compiler.
    // The JRE thinks that Box<String> and Box<Integer> are the same class.
    assertEquals("Box<String> = Box<Integer> class", strBox.getClass(), intBox.getClass());
  }
  
  
  public void test_Box_wildcard() {
    Box<?> intBox = new Box<Integer>(42);
    
    // Show that what you put in is what you get out.
    assertEquals("Box(42).getData()", 42, intBox.getData());
    
    //int x = intBox.getData();    
    
    
    
    // Verify the type of the returned object.
    assertEquals("Box<Integer>.getData()type", "class java.lang.Integer", intBox.getData().getClass().toString());
    
    Box<?> strBox = new Box<String>("Howdy");
    
    // The following line should not compile -- "incompatible type" error.
    intBox = new Box<String>("Hello");
    
    // The following line gives a "cannot find symbol" error when 
    // compiled because the constructor call doesn't match its defined signature.
    //intBox = new Box<Integer>("Hello");
    
    String s = (String) intBox.getData();
    
    // Show that what you put in is what you get out.
    assertEquals("Box(Howdy).getData()", "Howdy", strBox.getData());
    // Verify the type of the returned object.
    assertEquals("Box<String>.getData()type", "class java.lang.String", strBox.getData().getClass().toString());
    
    // Evidence of type erasure by the compiler.
    // The JRE thinks that Box<String> and Box<Integer> are the same class.
    assertEquals("Box<String> = Box<Integer> class", strBox.getClass(), intBox.getClass());
    
    // The following line won't compile because Box<Number> is not related to Box<Integer>
    // Box<Number> numBox = new Box<Integer>(31);
    
    // The following line is ok because numBox is not restricted to just Box<Number> 
    Box<? extends Number> numBox = new Box<Integer>(31);
    
    
  }
  
  
  public void test_variance() {
    Box<Integer> ib = new IntBox(23);
    
    
    Box<?> b1 = new Box<Integer>(13);
    Box<?> b2 = new Box<String>("Hello");  
    
  }
  
  public void test_holdsSuperClassOf() {
    Box<Integer> intBox = new Box<Integer>(5);
    Box<Number> numBox = new Box<Number>(3.5);
    Box<String> strBox = new Box<String>("Hmmmm...");
    SpecialBox<Integer> spBox = new SpecialBox<Integer>(42);
    
    // Integer is not a subclass of Double (held in the numBox)
    assertFalse("intBox.holdsSuperClassOf(numBox)", intBox.holdsSuperClassOf(numBox));
    
    // Integer is a subclass of Integer
    assertTrue("spBox.holdsSuperClassOf(intBox)", spBox.holdsSuperClassOf(intBox));
        
   // Integer is a subclass of Integer
    assertTrue("intBox.holdsSuperClassOf(spBox)", intBox.holdsSuperClassOf(spBox));
    
    // String is not a subclass of Integer
    assertFalse("strBox.holdsSuperClassOf(intBox)", strBox.holdsSuperClassOf(intBox));
  }
  
}
